﻿#pragma once

#include <windows.h> 
#include <iostream> 
#include <vector>
#include <sstream>
#include <opencv2\opencv.hpp>

class Pipe
{
public:

	std::string pipeName;
	
public:

	Pipe(std::string pipeName0 = "testpipe")
		: pipeName(pipeName0)
	{

	}

	virtual HANDLE StartClient()
	{
		return NULL;
	}

	static HANDLE ClientPipe(std::string pipeName = "testpipe")
	{
		std::string pn = "\\\\.\\pipe\\";
		pn = pn + pipeName;

		HANDLE hPipe;
		if (!WaitNamedPipeA(pn.c_str(), NMPWAIT_WAIT_FOREVER))
		{
			//std::cout << "WaitNamedPipe fail" << std::endl;
			return NULL;
		}

		hPipe = CreateFileA(pn.c_str(), GENERIC_READ | GENERIC_WRITE,
			0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		if (INVALID_HANDLE_VALUE == hPipe)
		{
			//std::cout << "CreateFile fail" << std::endl;
			hPipe = NULL;
			return NULL;
		}

		return hPipe;
	};

	static void Write(const std::string &str, HANDLE hPipe)
	{
		DWORD n = str.size();
		WriteFile(hPipe, str.c_str(), n, &n, NULL);
		std::cout << "Write: " << str << '\n';
	}

	static void Read(std::string &str, HANDLE hPipe, DWORD bufSize = 1024)
	{
		DWORD dwRead = bufSize;
		char *buf=new char[bufSize];
		str.clear();
		while (ReadFile(hPipe, buf, bufSize, &dwRead, NULL))
		{
			str.insert(str.size(), buf, dwRead);
			if (dwRead < bufSize)
				break;
		}
		delete buf;
		std::cout << "Read: " << str << '\n';
	}

	HANDLE ServerPipe(HANDLE &hClient, DWORD bufSize = 1024)
	{
		std::string pn = "\\\\.\\pipe\\";
		pn = pn + pipeName;

		HANDLE hPipe = CreateNamedPipeA(pn.c_str(),
			PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
			0, 1, bufSize, bufSize, 0, NULL);
		if (INVALID_HANDLE_VALUE == hPipe)
		{
			//std::cout << "CreateNamedPipe fail" << std::endl;
			hPipe = NULL;
			return hPipe;
		}

		HANDLE hEvent;
		hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
		if (!hEvent)
		{
			//std::cout << "CreateEvent fail" << std::endl;
			CloseHandle(hPipe);
			hPipe = NULL;
			return hPipe;
		}
		OVERLAPPED ovlap;
		ZeroMemory(&ovlap, sizeof(OVERLAPPED));
		ovlap.hEvent = hEvent;
		if (!ConnectNamedPipe(hPipe, &ovlap))
		{
			if (ERROR_IO_PENDING != GetLastError())
			{
				//std::cout << "ConnectNamedPipe fail" << std::endl;
				CloseHandle(hPipe);
				CloseHandle(hEvent);
				hPipe = NULL;
				return hPipe;
			}
		}

		hClient=StartClient();

		if (WAIT_FAILED == WaitForSingleObject(hEvent, INFINITE))
		{
			//std::cout << "WaitForSingleObject fail" << std::endl;
			CloseHandle(hPipe);
			CloseHandle(hEvent);
			hPipe = NULL;
			return hPipe;
		}
		CloseHandle(hEvent);

		return hPipe;
	};

	static void WaitClient(HANDLE hClient)
	{
		//wait until a file is finished printing
		if (hClient != NULL)
		{
			::WaitForSingleObject(hClient, INFINITE);
			::CloseHandle(hClient);
		}
	}

	static bool ClientWrite(const std::string &str, std::string pipename = "testpipe")
	{
		HANDLE h = ClientPipe(pipename);
		if (h == NULL)
			return false;
		Write(str, h);
		CloseHandle(h);
		return true;
	}

	static bool ClientRead(std::string &str, std::string pipename = "testpipe")
	{
		HANDLE h = ClientPipe(pipename);
		if (h == NULL)
			return false;
		Read(str, h);
		CloseHandle(h);
		return true;
	}

	bool ServerWrite(const std::string &str)
	{
		HANDLE hc = NULL;
		HANDLE h = ServerPipe(hc);
		if (h == NULL)
			return false;
		Write(str, h);
		CloseHandle(h);
		WaitClient(hc);
		return true;
	}

	bool ServerRead(std::string &str)
	{
		HANDLE hc = NULL;
		HANDLE h = ServerPipe(hc);
		if (h == NULL)
			return false;
		Read(str, h);
		CloseHandle(h);
		WaitClient(hc);
		return true;
	}
#if 0	
	static bool WritePos(float x, float y, float z,
		float rx, float ry, float rz,
		std::string seg = ",",
		std::string pipename = "testpipe")
	{
		std::ostringstream oss;
		oss << x << seg << y << seg << z << seg
			<< rx << seg << ry << seg << rz << seg;
		std::string str = oss.str();

		return ClientWrite(str, pipename);
	}

	static bool WritePos(cv::Vec6f p,
		std::string seg = ",",
		std::string pipename = "testpipe")
	{
		return WritePos(p[0], p[1], p[2], p[3], p[4], p[5], seg, pipename);
	}

	static bool WritePath(const std::vector<cv::Vec6f> &path,
		std::string seg = ",",
		std::string pipename = "testpipe")
	{
		std::ostringstream oss;
		for (size_t i = 0;i<path.size();i++)
			oss << path[i][0] << seg << path[i][1] << seg << path[i][2] << seg
			<< path[i][3] << seg << path[i][4] << seg << path[i][5] << seg;

		std::string str = oss.str();
		return ClientWrite(str, pipename);
	}
#endif





};